<template>
	<view class="pr">
		<view class="fww fjs list">
			<view :style="{width:width+'rpx', height:height+'rpx'}" class="p1 pr" :id="'item_' + i" v-for="(item, i) in list"
			 :key="i" :data-index="i" @touchstart='dragStart' @touchmove.stop.prevent='dragMove' @touchend='dragEnd'>
				<image mode="aspectFill" @click="preview(list, i)" class="wt ht mb4" :src="filter.image(item[field] || item)" />
				<view v-if="item.progress!==undefined && item.progress!==100" :style="{width:width+'rpx',height:height+'rpx'}" class="pa l0 t0 bd fjc">
					<u-loadmore :loadText="{loading:''}" status="loading" />
				</view>
				<view v-if="item.exam != 2 || item.progress===100" @click.stop="showDel(i)" class="pa bg-red cw t0 r0">
					<u-icon name="close" />
				</view>
			</view>
			<view v-if="max > list.length" :style="{width:width+'rpx',height:height+'rpx'}" class="my1 fdc fjc bd c9" @click="choose">
				<u-icon name="camera" size="50rpx"/>
				<view class="fs26">{{text}}</view>
			</view>
		</view>
		<view :style="{width:width+'rpx',height:height+'rpx',left: clone.left + 'px', top: clone.top + 'px'}" v-show="cloneShow" class="p1 pa item">
			<image mode="aspectFill" @click="preview(list, i)" class="wt ht" :src="filter.image(clone[field])" />
		</view>
		<u-modal :show="editShow" ref="uModal" width="auto" :show-title="false" :show-confirm-button="false">
		  <Crop v-model:value="image" @confirm="cuted" @end="editShow=false" />
		</u-modal>
		<u-modal :show="delShow" @confirm="del()" confirm-text="确定" title="删除图片" :show-cancel-button="true">
		  <view class="fjc py8">
				<image class="w12 h12" :src="filter.image(delUrl)" />
			</view>
		</u-modal>
		<view class="w0 h0 oh pr">
			<!-- #ifdef H5 -->
			<canvas type="2d" class="pa" :style="{width: '3000px', height: '3000px', left: '-3000px', top: '-3000px'}" canvas-id="cropper" id="cropper" />
			<!-- #endif -->
			<!-- #ifndef H5 -->
			<canvas class="pa" :style="{width: '3000px', height: '3000px', left: '-3000px', top: '-3000px'}" canvas-id="cropper" id="cropper" />
			<!-- #endif -->
		</view>
	</view>
</template>

<script lang="ts">
import util from '@/utils/util'
import filter from '@/utils/filter'
import api from '@/config/api'
import Emitter from 'uview-plus/libs/util/emitter'

export default {
	mixins: [Emitter],
	props: {
		value: {
			type: [String, Array],
			default: ''
		},
		field: {
			type: String,
			default: 'url'
		},
		mult: {
			type: Boolean,
			default: true
		},
		max: {
			type: [String, Number],
			default: 1
		},
		text: {
			type: String,
			default: ''
		},
		width: {
			type: [String, Number],
			default: 160
		},
		height: {
			type: [String, Number],
			default: 160
		},
		origil: {
			type: Boolean,
			default: false
		},
		needcut: {
			type: Boolean,
			default: false
		},
		size: {
			type: Number,
			default: 0
		}
	},
	data() {
		return {
			filter: filter,
			image:'',
			tempFiles:[],
			index:0,
			start: 0,
			list:[],
			editShow:false,
			delShow:false,
			handing: false,
			delId:-1,
			delUrl:'',
			distance:{x:0, y:0},
			cut:{x:0,y:0,w:640,h:640},
			box:{left:0, top:0, width:0, height:0},
			clone:{
				top:0,
				left:0
			},
			cloneShow:false,
			replace:{
				xt:'',
				name:'',
				subname:''
			}
		}
	},
	created () {
		this.ctx = uni.createCanvasContext('cropper', this)
	},
	mounted () {
		this.load(this.value)
	},
	methods: {
		load (val) {
			if(parseInt(this.max) > 1){
				this.list = val
			} else {
				this.list = val ? [{[this.field]: val}] : []
			}
		},
		// 剪裁图片
		choose(){
			const that = this
			this.start = this.list.length
			uni.chooseImage({
				count: this.max - this.start, 
				sizeType: ['original'],
				success({tempFiles}){
					that.index = 0
					that.tempFiles = tempFiles
					if(that.needcut){
						that.image = that.tempFiles[that.index]
						that.editShow = true
					} else {
						that.handle(0)
					}
				}
			})
		},
		handle(i){
			if(i >= this.tempFiles.length){
				return
			}
			this.image = this.tempFiles[i]
			if(this.size > 0 && this.image.size > this.size * 1024){
				util.msg('图片超出大小')
				return
			} else {
				this.compress(this.image.path, i)
			}
		},
		// 压缩图片
		async compress(val, i){
			const {width, height} = await uni.getImageInfo({src: val})
			if(this.origil){
				await this.todataOrigil(val, {
					x: 0,
					y: 0,
					w: width,
					h: height
				}, i)
			} else {
				await this.todata(val, {
					x: 0,
					y: 0,
					w: width,
					h: height
				}, i)
			}
		},
		// 剪裁完成
		async cuted(img={}){
			if(this.handing || this.index >= this.tempFiles.length){
				return
			}
			this.index += 1
			this.handing = true
			await this.todata(this.image.path, img, this.index - 1)
			if(this.index >= this.tempFiles.length){
				this.editShow = false
			} else {
				this.image.path = this.tempFiles[this.index]
			}
		},
		// 转化为图片数据
		async todata(src, cut={}, i = 0){
			const scale = cut.h / cut.w
			this.ctx.drawImage(src, cut.x, cut.y, cut.w, cut.h, 0, 0, 640, 640 * scale)
			const that = this
			this.ctx.draw(false, ()=>{
				that.handing = false
				uni.canvasToTempFilePath({
					x: 0,
					y: 0,
					width: 640,
					height: 640 * scale,
					destWidth: 640,  // 输出图片宽度（默认为 width * 屏幕像素密度）
					destHeight: 640 * scale,  // 输出图片高度（默认为 height * 屏幕像素密度）
					canvasId: 'cropper',
					fileType: 'jpg',
					success({tempFilePath}){
						that.upload(tempFilePath, i)
					}
				}, that)
			})		
		},
		// 转化为图片数据
		async todataOrigil(src, cut={}, i = 0){
			// const scale = cut.h / cut.w
			this.ctx.drawImage(src, cut.x, cut.y, cut.w, cut.h, 0, 0, cut.w, cut.h)
			const that = this
			this.ctx.draw(false, ()=>{
				that.handing = false
				uni.canvasToTempFilePath({
					x: 0,
					y: 0,
					width: cut.w,
					height: cut.h,
					destWidth: cut.w,  // 输出图片宽度（默认为 width * 屏幕像素密度）
					destHeight: cut.h,  // 输出图片高度（默认为 height * 屏幕像素密度）
					canvasId: 'cropper',
					fileType: 'jpg',
					success({tempFilePath}){
						that.upload(tempFilePath, i)
					}
				}, that)
			})		
		},
		// 上传
		async upload(e, index){
			// const that = this
			const i = this.start + index
			// 如果列表还没处理完
			this.list[i] = {[this.field]: e, progress:0}
			const {statusCode, data} = await uni.uploadFile({
				url: api.upload, // 接口地址
				filePath: e,
				name: 'file'
			}).catch(err=>{})
			statusCode===200 && this.success(data, index)
		},
		success (url, index) {
			const i = this.start + index
			this.list[i] && Object.assign(this.list[i], {[this.field]: url, progress: 100})
			let val = url
			if(this.max > 1){
				if(index + 1 >= this.tempFiles.length){
					val = this.list.filter(r=>r.progress===undefined || r.progress===100)
					this.$emit('update:value', this.mult ? val : val.map(r=>r[this.field]||r))
				} else if (!this.needcut) {
					this.handle(index + 1)
				}
			} else if (this.max == 1) {
				this.$emit('update:value', url)
				this.$emit('confirm', url)
			}
			setTimeout(() => {
				this.dispatch('u-form-item', 'onFieldChange', val)
			}, 40)
		},
		preview (urls, i) {
			util.preview(urls, i)
		},
		showDel(i) {
			this.delId = i
			const item = this.list[i]
			this.delUrl = item[this.field] || item
			this.delShow = true
		},
		del(){
			this.max > 1 ? this.list.splice(this.delId, 1) : (this.list = [])
			const val = this.max > 1 ? this.list : ''
			this.$emit('update:value', val)
			this.$emit('confirm', val)
			setTimeout(() => {
				this.dispatch('u-form-item', 'onFieldChange', val)
			}, 40)
		},
		dragStart (e) {
			const i = e.currentTarget.dataset.index
			Object.assign(this.clone, this.list[i])
			// box
			uni.createSelectorQuery().in(this).select('.list').boundingClientRect(({top,left,width,height}) => {
				this.box.left = left
				this.box.top = top
				this.box.width = width
				this.box.height = height
			}).exec()	
			// 当前选项
			uni.createSelectorQuery().in(this).select('#item_' + i).boundingClientRect(({top,left,width,height}) => {
				this.distance.x = e.changedTouches[0].clientX - left + this.box.left
				this.distance.y = e.changedTouches[0].clientY - top + this.box.top
				this.clone.w = width
				this.clone.h = height
				this.clone.top = e.changedTouches[0].clientY - this.distance.y
				this.clone.left = e.changedTouches[0].clientX - this.distance.x
			}).exec()
			this.cloneShow = true
		},
		dragMove ({changedTouches}) {
			this.clone.top = changedTouches[0].clientY - this.distance.y
			this.clone.left = changedTouches[0].clientX - this.distance.x
			if(this.clone.top < 0) {
				this.clone.top = 0
			} else if (this.clone.top > this.box.height - this.clone.h) {
				this.clone.top = this.box.height - this.clone.h
			}
			if(this.clone.left < 0) {
				this.clone.left = 0
			} else if (this.clone.left > this.box.width - this.clone.w) {
				this.clone.left = this.box.width - this.clone.w
			}
		},
		dragEnd (e) {
			const x = e.changedTouches[0].clientX - this.box.left
			const y = e.changedTouches[0].clientY - this.box.top
			const cols = Math.floor(this.box.width / this.clone.w)
			const target = Math.floor(y / this.clone.h) * cols + Math.floor(x / this.clone.w)
			const i = e.currentTarget.dataset.index

			if (target >= 0 && target < this.list.length && target != i) {
				const replace = {}
				Object.assign(replace, this.list[target])
				this.list[target] = this.list[i]
				this.list[i] = replace
			}
			this.cloneShow = false
		}
	},
	watch: {
		value(newVal, oldVal){
			this.load(this.value)
		}
	}
}
</script>
